/* $RCSFile: BaseDataType.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/UI/DataTypes/BaseDataType.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:29  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;

using AddonNice.Diagnostics;
using AddonNice.UI;
using AddonNice.UI.WebControls;
using AddonNice.Configuration;
using AddonNice.Settings;

using AddonNice.CRMWrapper;

using Telerik.Web.UI;

namespace AddonNice.UI.DataTypes
{
  	#region delegate for DataType

    /// <summary>
    /// Used in conjonction with Handle change
    /// Changed is for an even triggered from the interface
    /// EditorSet is when the Editor for this DataType is changed
    /// Loaded when the value is changed from reading db value / opposed to values set from interface or from constructor
    /// </summary>
    public enum DataTypeEventType { Unknown=0,Changed,ReBound,EditorSet,Loaded }; 


	/// <summary>
	/// define a custom event class for DataType
	/// </summary>
	public class DataTypeEventArgs : EventArgs
	{
        public DataTypeEventType EventType          =   DataTypeEventType.Unknown;
        public object Data                          =   null;
        public EventArgs Args                       =   new EventArgs();
        public string oldVal                        =   string.Empty;
        public string newVal                        =   string.Empty;

		public DataTypeEventArgs(DataTypeEventType tp,string oldval,string newval)
		{
            EventType               =   tp;
            oldVal                  =   oldval;
            newVal                  =   newval;
		}

		public DataTypeEventArgs(DataTypeEventType tp,object data)
		{
            EventType               =   tp;
            Data                    =   data;
		}
		public DataTypeEventArgs(DataTypeEventType tp,object data,EventArgs args)
		{
            EventType               =   tp;
            Data                    =   data;
            Args                    =   args;
		}

		public DataTypeEventArgs(DataTypeEventType tp,object sender,EventArgs args,string oldval,string newval)
		{
            EventType               =   tp;
            Data                    =   sender;
            Args                    =   args;
            oldVal                  =   oldval;
            newVal                  =   newval;
		}
	}

    // define a new delegate that use our custom eventArg class above
	public delegate void DataTypeEventHandler(object sender, DataTypeEventArgs e);

	#endregion delegate for DataType

    
    /// <summary>
	/// BaseDataType class is used to manage data inside SettingsItems
    /// It allow editing of values in propertyPages
	/// </summary>
	public abstract class BaseDataType 
	{
		/// <summary>
		/// Holds the value
		/// </summary>
		protected PropertiesDataType	InnerDataType;
		protected object				InnerDataSource;
		protected Control				innerControl;
        protected bool                  _Ok4Validators      =   true;
		protected Unit					_controlWidth       =   new Unit("100%");
        protected bool                  _FullWidth          =   false;
		protected string				innerValue          =   string.Empty;
        public  bool                    _UsesRadControl     =   Config.UseRadControlsForSettings;
        protected bool                  _ReadOnly           =   false;
        protected bool                  _IsInitialized      =   false;
        public  bool                    HandleChanges       =   false;

        #region Events and handler
        // Event Handler for call back
        public event DataTypeEventHandler DataTypeEvent;

		// extension to have a call back on main events 
        public virtual void OnDataTypeEvent(DataTypeEventArgs e)
		{
            if ( DataTypeEvent != null )
            {
                if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType OnDataTypeEvent e.EventType: {0}",e.EventType),DataTypeTraceSwitch.Sw.Info);
                DataTypeEvent(this, e);
            }
		}

        /// <summary>
        /// Inform all subscribers  when text is changed, handler must have been installed
        /// </summary>
        protected void tx_TextChanged(object sender, EventArgs e)
        {
    		if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType tx_TextChanged sender: {0}",sender),DataTypeTraceSwitch.Sw.Info);
            string oldValue         =   Val;
            ReadDataFromEditControl();
            string newValue         =   Val;
            OnDataTypeEvent(new DataTypeEventArgs(DataTypeEventType.Changed,sender,e,oldValue,newValue));
        }

        #endregion Events and handler

        #region Properties

		private PortalSettings _portalSettings;
		/// <summary>
		/// Stores current portal settings 
		/// </summary>
		public PortalSettings portalSettings
		{
			get
			{
				if(_portalSettings == null)
				{
					// Obtain PortalSettings from Current Context
					if (HttpContext.Current != null)
                    {
						_portalSettings = (PortalSettings) HttpContext.Current.Items[StStr.strPortalSettings];
                        if ( _portalSettings == null )
						    _portalSettings = (PortalSettings) HttpContext.Current.Items[StStr.strPortalSettings_Loading];
                    }
				}
				return _portalSettings;
			}
		}

        protected CRMWrapperBase Wrapper
        {
            get { return AddonNice.Security.PortalSecurity.Wrapper; }
        }

        protected void ResetWrapper(DynEntity dynEnt)
        {
            CRMWrapperBase  w   =   Wrapper;
            if ( !dynEnt.HasWrapper(w) )
                dynEnt.SetWrapper(w);
        }

        /// <summary>
        /// When set, try to propagate to EditControl
        /// </summary>
        public virtual Unit controlWidth
        {
            get
            {
                return _controlWidth;
            }
            set
            {
                _controlWidth = value;
                if (IsInitialized)
                {
                    Control ctl = EditControl;
                    if (ctl != null && ctl is WebControl)
                        ((WebControl)ctl).Width = value;
                }

            }
        }

        public bool Ok4Validators
        {
            get
            {
                return _Ok4Validators;
            }
            set
            {
                _Ok4Validators = value;
            }
        }
        
        public bool UseRadControl
        {
            get
            {
                return _UsesRadControl;
            }
            set
            {
                _UsesRadControl = value;
                if (_IsInitialized)
                    InitializeComponents();
            }
        }
        
        /// <summary>
        /// True when the datatype has its editor set
        /// </summary>
        public bool IsInitialized
        {
            get
            {
                return _IsInitialized;
            }
        }

        /// <summary>
        /// Set by Parent item, when true the control.enable property is set to false
        /// </summary>
        public virtual bool ReadOnly
        {
            get
            {
                return _ReadOnly;
            }
            set
            {
                if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ReadOnly SET value: {0}",value),DataTypeTraceSwitch.Sw.Info);
                _ReadOnly   =   value;
            }
        }

        /// <summary>
        /// Simple accessor to allow check something
        /// </summary>
        public Control InnerControl
        {
            get
            {
                return innerControl;
            }
        }

        protected object _DataSource  =   null;
        /// <summary>
		/// Gets DataSource
		/// Should be overrided from inherited classes
		/// </summary>
		public virtual object DataSource
		{
			get
			{
				return _DataSource;
			}
			set
			{
				_DataSource =   value;
			}
		}


		public virtual string DataValueField
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

		public virtual string DataTextField
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

        /// <summary>
        /// Used mainly by FolderDataType
        /// </summary>
		public virtual string baseDirectory
		{
			get
			{
				throw new NotImplementedException("baseDirectory");
			}
			set
			{
				throw new NotImplementedException("baseDirectory");
			}
		}

        public virtual string FullPath
		{
			get
			{
				throw new NotImplementedException("FullPath");
			}
		}
       
        /// <summary>
        /// Update value from control: used by eventhandler after a control change event triggered
        /// </summary>
        public virtual string ReadDataFromEditControl()
		{
            Control Ctl =   EditControl;
            if (DataTypeTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ReadDataFromEditControl BEG Control is null: {0}, Val: {1}.", (Ctl == null), Val ), DataTypeTraceSwitch.Sw.Info);
            if ( Ctl ==   null )
                return Val;
            // DO NOT use Val but use InnerValue which do a DataBind on set
            if (UseRadControl)
            {
                if ( Ctl is RadTextBox)
                {
                    RadTextBox Tx   =   (RadTextBox)Ctl;
                    innerValue      =   Tx.Text;
                    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ReadDataFromEditControl UseRadControl Value: {0}", innerValue),DataTypeTraceSwitch.Sw.Info);
                }
            }
            else
            {
                if ( Ctl is TextBox )
                {
                    TextBox Tx      =   (TextBox)Ctl;
                    innerValue      =   Tx.Text;
                }
            }
            if (DataTypeTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ReadDataFromEditControl END InnerValue: {0}.", innerValue), DataTypeTraceSwitch.Sw.Info);
            return Val;
        }

       /// <summary>
        /// If the underlying control assume it own required validator, no use to add one in setting table
        /// </summary>
        public virtual bool SelfRequiredValidator
        {
            get { return false; }
        }

        /// <summary>
        /// Used by Setting item to propagate required
        /// </summary>
        public virtual void SetRequired(bool req)
        {}

        /// <summary>
        /// If the underlying control assume it own range validator, no use to add one in setting table
        /// </summary>
        public virtual bool SelfRangeValidator
        {
			get{return false;}
		}
        /// <summary>
        /// Used by Setting item to propagate min/max values
        /// </summary>
        public virtual void SetMinValue(double minVal)
        {}
        /// <summary>
        /// Used by Setting item to propagate min/max values
        /// </summary>
        public virtual void SetMaxValue(double maxVal)
        {}
        
        /// <summary>
        /// Setting an EditControl triggers reading of value in the control
        /// </summary>
        public virtual Control EditControl
		{
			get
			{
                bool iCtrlDefined   =    ( innerControl != null );
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl GET iCtrlDefined : {0}", iCtrlDefined ),DataTypeTraceSwitch.Sw.Info);
				if ( !iCtrlDefined )
					InitializeComponents();
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl GET Value2Save: [{0}]", Value2Save),DataTypeTraceSwitch.Sw.Info);
				//Return control
				return innerControl;
			}
			set
			{
                bool iCtrlDefined   =    ( innerControl != null );
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl SET iCtrlDefined : {0}", iCtrlDefined ),DataTypeTraceSwitch.Sw.Info);
                bool iCtrlDefinedEqual  =   ( iCtrlDefined && innerControl.Equals(value) );
			    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl SET innerControl equal to value : {0}", iCtrlDefinedEqual ),DataTypeTraceSwitch.Sw.Info);
                if (UseRadControl)
                {
                    if (value is RadTextBox)
                    {
                        if (!iCtrlDefinedEqual)
                        {
                            RadTextBox Tx   =   (RadTextBox)value;
                            innerControl    =   value;
                            if (HandleChanges)
                            {
                                Tx.AutoPostBack = true;
                                Tx.TextChanged += new EventHandler(tx_TextChanged);
                            }
                        }
                        //Update value from control
                        // DO NOT use Val but use InnerValue
                        innerValue          =   ((RadTextBox)innerControl).Text;
                        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl UseRadControl Set Value: {0}", innerValue),DataTypeTraceSwitch.Sw.Info);
                        return;
                    }
                }
                else
                {
                    if (value is TextBox)
                    {
                        if (!iCtrlDefinedEqual)
                        {
                            TextBox Tx      =   (TextBox)value;
                            innerControl    =   value;
                            if (HandleChanges)
                            {
                                Tx.AutoPostBack = true;
                                Tx.TextChanged += new EventHandler(tx_TextChanged);
                            }
                        }
                        //Update value from control
                        // DO NOT use Val but use InnerValue
                        innerValue          =   ((TextBox)innerControl).Text;
                        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType EditControl Set Value: {0}", innerValue),DataTypeTraceSwitch.Sw.Info);
                        return;
                    }
                }
				string msg  =   string.Format("[E]BaseDataType Set EditControl: {0}, not TextBox",value.GetType());
				if ( DataTypeTraceSwitch.Sw.TraceError )
                    Trace.WriteLine(msg,DataTypeTraceSwitch.Sw.Info);
				throw new ArgumentException(msg);
			}
		}

		public virtual PropertiesDataType Type
		{
			get
			{
				return InnerDataType;
			}
		}

		// CS 10/04
		public virtual string Value2Save
		{
			get
			{
				return Val;
			}
		}
		
		public virtual string Val
		{
			get
			{
				return innerValue;
			}
			set
			{
				if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType Value SET new value: {0}", value),DataTypeTraceSwitch.Sw.Info);
				innerValue = value;
		        if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType Value SET innerControl is NULL: {0}", innerControl== null),DataTypeTraceSwitch.Sw.Info);
                if ( innerControl == null )
                    return;
                if ( UseRadControl )
                {
                    if (innerControl is RadTextBox)
                    {
                        //Update value in control
                        ((RadTextBox)innerControl).Text = value;
                        return;
                    }
                }
                else if (innerControl is TextBox)
                {
                    //Update value in control
                    ((TextBox)innerControl).Text = value;
                    return;
                }
                string msg = string.Format("[V]BaseDataType Value SET innerControl is : {0}", innerControl);
		        if ( DataTypeTraceSwitch.Sw.TraceError)
                    Trace.WriteLine( msg,DataTypeTraceSwitch.Sw.Info);
                throw new Exception(msg);
			}
		}

		/// <summary>
		/// This triggers a new row in setting table to contain the edit control with colspan=3
		/// </summary>
		public virtual bool FullWidth
		{
			get{return _FullWidth;}
            set { _FullWidth = value; }
		}
		
		
		public virtual string Description
		{
			get
			{
				return string.Empty;
			}
		}

		public virtual bool HasCrmEntity
		{
			get
			{
				return false;
			}
		}

		public virtual string CrmEntity
		{
			get
			{
				return string.Empty;
			}
            set
            {}
		}

        #endregion Properties

        #region Internal methods to override

        /// <summary>
        /// By default create a text box, to define for special purposes
        /// If UseRadControl is true, creates a RadTextBox
        /// </summary>
		protected virtual void InitializeComponents()
		{
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType InitializeComponents Creating TextBox for datatype description: {0}, UseRadControl: {1}, ReadOnly: {2}",
                    Description,_UsesRadControl,ReadOnly),DataTypeTraceSwitch.Sw.Info);
            if ( UseRadControl )
            {
                RadTextBox tx       =   new RadTextBox();
                tx.Width            =   controlWidth;
                if (HandleChanges)
                {
                    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( "[V]BaseDataType InitializeComponents Rad HandleChanges set",DataTypeTraceSwitch.Sw.Info);
                    tx.AutoPostBack =   true;
                    tx.TextChanged  +=  new EventHandler(tx_TextChanged);
                }
                if ( ReadOnly )
                    tx.Enabled      =   false;
                innerControl        =   tx;
            }
            else 
            {
                TextBox tx          =   new TextBox();
                tx.CssClass         =   "NormalTextBox";
                tx.Columns          =   30;
                tx.Width            =   controlWidth;
                if (HandleChanges)
                {
                    if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( "[V]BaseDataType InitializeComponents HandleChanges set",DataTypeTraceSwitch.Sw.Info);
                    tx.AutoPostBack =   true;
                    tx.TextChanged  +=  new EventHandler(tx_TextChanged);
                }
                if ( ReadOnly )
                    tx.Enabled      =   false;
                innerControl        =   tx;
            }
            _IsInitialized          =   true;
		}

        public virtual void ResetControl()
        {
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ResetControl BEG for: {0}, IsInitialized: {1}", this,IsInitialized),DataTypeTraceSwitch.Sw.Info);
            _IsInitialized  =   false;
            innerControl    =   null;
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ResetControl END for: {0}, IsInitialized: {1}", this,IsInitialized),DataTypeTraceSwitch.Sw.Info);
        }


        /// <summary>
        /// Called by SettingItem to bind their values to controls
        /// Need to be overriden in child classes
        /// </summary>
        public virtual void DataBind()
        {
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType DataBind BEG for: {0}, UseRadControl: {1}", this,UseRadControl),DataTypeTraceSwitch.Sw.Info);
            if ( UseRadControl )
                ((RadTextBox)innerControl).Text = Value2Save;
			else ((TextBox) innerControl).Text = Value2Save;
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]BaseDataType DataBind END.",DataTypeTraceSwitch.Sw.Info);
        }


        /// <summary>
        /// Allow a soft datasource reset
        /// </summary>
        public virtual void ResetDataSource(object newDataSrc,string SelVal)
        {
			if ( DataTypeTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]BaseDataType ResetDataSource not handled for: {0}, SelVal: {1}", this,( SelVal == null )? string.Empty:SelVal),DataTypeTraceSwitch.Sw.Info);
        }

        #endregion Internal methods to override
	}
}